Skip to content

fix: Honor EnumMember attribute in query-string serialization#241

Merged
gjtorikian merged 3 commits intomainfrom
fix/enum-query-string-serialization
Apr 28, 2026
Merged

fix: Honor EnumMember attribute in query-string serialization#241
gjtorikian merged 3 commits intomainfrom
fix/enum-query-string-serialization

Conversation

@gjtorikian
Copy link
Copy Markdown
Contributor

Summary

  • Query-string serializer now reads [EnumMember(Value="...")] instead of falling back to Enum.ToString(), so enum values like PaginationOrder.Desc serialize as desc (not Desc) on the wire
  • ListOptions.Order is now PaginationOrder? (nullable) so callers can omit the order query parameter entirely
  • Fixes pre-existing test compilation failure in NonGetQueryParamsTest caused by the DeleteResourceByExternalIdDeleteResource rename

Test plan

  • dotnet build succeeds (0 errors, 0 warnings)
  • dotnet test passes all 437 tests
  • Verify against live API that OrganizationsService.ListAsync no longer returns a validation error for the order parameter

🤖 Generated with Claude Code

The query-string builder used Enum.ToString(), producing
PascalCase values like "Desc" that the API rejects. It now
reads [EnumMember(Value="...")] to emit the correct wire
values ("desc", "asc").

Also makes ListOptions.Order nullable so callers can omit
the parameter entirely instead of always sending a value.
The test still referenced the old
DeleteResourceByExternalId method signature, which was
removed in 4ceb3de. Updated to use the current
DeleteResource API so the test project compiles.
@gjtorikian gjtorikian requested review from a team as code owners April 27, 2026 21:08
@gjtorikian gjtorikian requested a review from marji-workos April 27, 2026 21:08
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR fixes query-string enum serialization by introducing ResolveEnumWireValue, which reads [EnumMember(Value="...")] so values like PaginationOrder.Desc serialize as desc rather than Desc. It also makes ListOptions.Order nullable (while preserving the PaginationOrder.Desc default) so callers can pass null to omit the order parameter entirely, and updates a test that was broken by the earlier DeleteResourceByExternalIdDeleteResource rename.

Confidence Score: 5/5

This PR is safe to merge — all three changes are targeted, backward-compatible, and well-scoped.

No P0 or P1 issues found. The ResolveEnumWireValue logic is correct for all non-[Flags] enums (the [Flags] edge case was already noted in a previous review thread). The nullable Order field preserves the existing PaginationOrder.Desc default so no callers are affected. The test update is a straightforward rename fix.

No files require special attention.

Important Files Changed

Filename Overview
src/WorkOS.net/Client/Utilities/RequestUtilities.cs Adds ResolveEnumWireValue helper that reads [EnumMember(Value="...")] before falling back to ToString(), correctly fixing case-sensitive query-string serialization for enums like PaginationOrder.
src/WorkOS.net/Services/_common/_interfaces/ListOptions.cs Makes Order nullable (PaginationOrder?) while preserving the PaginationOrder.Desc default, so callers can explicitly set null to omit the order query parameter without changing any existing default behavior.
test/WorkOSTests/Client/NonGetQueryParamsTest.cs Updates test method calls from the renamed DeleteResourceByExternalIdDeleteResource API, fixing a pre-existing compilation failure; no logic changes to assertions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Enum property in options] --> B{value is null?}
    B -- Yes --> C[Skip property - omit from query]
    B -- No --> D[AddScalar switch on type]
    D --> E[case Enum: ResolveEnumWireValue]
    E --> F[GetField by name]
    F --> G{Field found?}
    G -- No --> H[Fallback: ToString]
    G -- Yes --> I{EnumMember attr present?}
    I -- No --> H
    I -- Yes --> J[Return attr.Value]
    J --> K[Append to query string]
    H --> K
Loading

Reviews (2): Last reviewed commit: "fix: Restore default desc ordering for l..." | Re-trigger Greptile

Comment thread src/WorkOS.net/Services/_common/_interfaces/ListOptions.cs Outdated
Comment on lines +381 to +394
private static string ResolveEnumWireValue(Enum value)
{
var member = value.GetType().GetField(value.ToString());
if (member != null)
{
var attr = member.GetCustomAttribute<EnumMemberAttribute>();
if (attr != null && attr.Value != null)
{
return attr.Value;
}
}

return value.ToString();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [Flags] enum combinations will miss the EnumMember lookup

value.GetType().GetField(value.ToString()) works correctly for simple enums, but for a [Flags] enum holding a combined value (e.g., A | B), ToString() produces "A, B" — a string that will never match any single field name, so GetField returns null and the method falls back to ToString(). No current PaginationOrder-style enum in this SDK uses [Flags], but this edge case is silently broken if any is added in the future. A defensive comment noting the limitation would prevent confusion.

Keep Order nullable (callers can set null to omit it) but
default to PaginationOrder.Desc so existing callers that
don't set Order explicitly still get order=desc on the wire.
@gjtorikian gjtorikian merged commit 6c2789a into main Apr 28, 2026
7 checks passed
@gjtorikian gjtorikian deleted the fix/enum-query-string-serialization branch April 28, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant